﻿#region

using System;
using System.Collections.Generic;

#endregion

namespace GGEditor.API.Utility.Collections
{
    public interface IStack<T>
    {
        int Count { get; }
        bool Empty { get; }
        void Clear();
        void Push(T item);
        T Pop();
        T Peek();
    }

    public interface IBoundedStack<T> : IStack<T>
    {
        int Capacity { get; }
    }

    public class InfiniteStack<T> : IStack<T>
    {
        private Stack<T> stack = new Stack<T>();

        #region IStack<T> Members

        public void Clear()
        {
            stack.Clear();
        }

        public int Count
        {
            get { return stack.Count; }
        }

        public bool Empty
        {
            get { return Count == 0; }
        }

        public void Push(T item)
        {
            stack.Push(item);
        }

        public T Pop()
        {
            return stack.Pop();
        }

        public T Peek()
        {
            return stack.Peek();
        }

        #endregion
    }

    public class BoundedStack<T> : IBoundedStack<T>
    {
        private readonly int capacity;
        private readonly IList<T> list;

        public BoundedStack(int capacity)
        {
            this.capacity = Contract.IsAtLeast(capacity, 0, "capacity");
            list = new List<T>();
        }

        #region IBoundedStack<T> Members

        public int Capacity
        {
            get { return capacity; }
        }

        public void Clear()
        {
            list.Clear();
        }

        public int Count
        {
            get { return list.Count; }
        }

        public bool Empty
        {
            get { return Count == 0; }
        }

        public void Push(T item)
        {
            if (Capacity == 0)
                return;
            list.Insert(0, item);
            if (Count > Capacity)
                list.RemoveAt(Count - 1);
        }

        public T Pop()
        {
            if (Empty)
                throw new InvalidOperationException("Stack is empty.");

            T item = list[0];
            list.RemoveAt(0);
            return item;
        }

        public T Peek()
        {
            if (Empty)
                throw new InvalidOperationException("Stack is empty.");

            return list[0];
        }

        #endregion
    }
}